package com.myview;

import android.content.Context;
import android.util.AttributeSet;

import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;

import android.content.res.TypedArray;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.youth.banner.BannerConfig;
import com.youth.banner.BannerScroller;
import com.youth.banner.WeakHandler;
import com.youth.banner.listener.OnBannerClickListener;
import com.youth.banner.listener.OnBannerListener;
import com.youth.banner.loader.ImageLoaderInterface;
import com.youth.banner.view.BannerViewPager;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;


    public class MyBanner extends FrameLayout implements ViewPager.OnPageChangeListener {
        public String tag = "banner";
        private int mIndicatorMargin = BannerConfig.PADDING_SIZE;
        private int mIndicatorWidth;
        private int mIndicatorHeight;
        private int indicatorSize;
        private int bannerStyle = BannerConfig.CIRCLE_INDICATOR;
        private int delayTime = BannerConfig.TIME;
        private int scrollTime = BannerConfig.DURATION;
        private boolean isAutoPlay = BannerConfig.IS_AUTO_PLAY;
        private boolean isScroll = BannerConfig.IS_SCROLL;
        private int mIndicatorSelectedResId = com.youth.banner.R.drawable.gray_radius;
        private int mIndicatorUnselectedResId = com.youth.banner.R.drawable.white_radius;
        private int titleHeight;
        private int titleBackground;
        private int titleTextColor;
        private int titleTextSize;
        private int count = 0;
        private int currentItem;
        private int gravity = -1;
        private int lastPosition = 1;
        private int scaleType = 1;
        private List<String> titles;
        private List imageUrls;
        private List<View> imageViews;
        private List<ImageView> indicatorImages;
        private Context context;
        private BannerViewPager viewPager;
        private TextView bannerTitle, numIndicatorInside, numIndicator;
        private LinearLayout indicator, indicatorInside, titleView;
        private ImageLoaderInterface imageLoader;
        private ViewPager.OnPageChangeListener mOnPageChangeListener;
        private BannerScroller mScroller;
        private OnBannerClickListener bannerListener;
        private OnBannerListener listener;
        private DisplayMetrics dm;

        private WeakHandler handler = new WeakHandler();
        private BannerPagerAdapter adapter;

        public MyBanner(Context context) {
            this(context, null);
        }

        public MyBanner(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }

        public MyBanner(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
            this.context = context;
            titles = new ArrayList<>();
            imageUrls = new ArrayList<>();
            imageViews = new ArrayList<>();
            indicatorImages = new ArrayList<>();
            dm = context.getResources().getDisplayMetrics();
            indicatorSize = dm.widthPixels / 80;
            initView(context, attrs);
        }

        private void handleTypedArray(Context context, AttributeSet attrs) {
            if (attrs == null) {
                return;
            }
            TypedArray typedArray = context.obtainStyledAttributes(attrs, com.youth.banner.R.styleable.Banner);
            mIndicatorWidth = typedArray.getDimensionPixelSize(com.youth.banner.R.styleable.Banner_indicator_width, indicatorSize);
            mIndicatorHeight = typedArray.getDimensionPixelSize(com.youth.banner.R.styleable.Banner_indicator_height, indicatorSize);
            mIndicatorMargin = typedArray.getDimensionPixelSize(com.youth.banner.R.styleable.Banner_indicator_margin, BannerConfig.PADDING_SIZE);
            mIndicatorSelectedResId = typedArray.getResourceId(com.youth.banner.R.styleable.Banner_indicator_drawable_selected, com.youth.banner.R.drawable.gray_radius);
            mIndicatorUnselectedResId = typedArray.getResourceId(com.youth.banner.R.styleable.Banner_indicator_drawable_unselected, com.youth.banner.R.drawable.white_radius);
            scaleType = typedArray.getInt(com.youth.banner.R.styleable.Banner_image_scale_type, scaleType);
            delayTime = typedArray.getInt(com.youth.banner.R.styleable.Banner_delay_time, BannerConfig.TIME);
            scrollTime = typedArray.getInt(com.youth.banner.R.styleable.Banner_scroll_time, BannerConfig.DURATION);
            isAutoPlay = typedArray.getBoolean(com.youth.banner.R.styleable.Banner_is_auto_play, BannerConfig.IS_AUTO_PLAY);
            titleBackground = typedArray.getColor(com.youth.banner.R.styleable.Banner_title_background, BannerConfig.TITLE_BACKGROUND);
            titleHeight = typedArray.getDimensionPixelSize(com.youth.banner.R.styleable.Banner_title_height, BannerConfig.TITLE_HEIGHT);
            titleTextColor = typedArray.getColor(com.youth.banner.R.styleable.Banner_title_textcolor, BannerConfig.TITLE_TEXT_COLOR);
            titleTextSize = typedArray.getDimensionPixelSize(com.youth.banner.R.styleable.Banner_title_textsize, BannerConfig.TITLE_TEXT_SIZE);
            typedArray.recycle();
        }

        private void initView(Context context, AttributeSet attrs) {
            imageViews.clear();
            View view = LayoutInflater.from(context).inflate(com.youth.banner.R.layout.banner, this, true);
            viewPager = (BannerViewPager) view.findViewById(com.youth.banner.R.id.bannerViewPager);
            titleView = (LinearLayout) view.findViewById(com.youth.banner.R.id.titleView);
            indicator = (LinearLayout) view.findViewById(com.youth.banner.R.id.circleIndicator);
            indicatorInside = (LinearLayout) view.findViewById(com.youth.banner.R.id.indicatorInside);
            bannerTitle = (TextView) view.findViewById(com.youth.banner.R.id.bannerTitle);
            numIndicator = (TextView) view.findViewById(com.youth.banner.R.id.numIndicator);
            numIndicatorInside = (TextView) view.findViewById(com.youth.banner.R.id.numIndicatorInside);
            handleTypedArray(context, attrs);
            initViewPagerScroll();
        }

        private void initViewPagerScroll() {
            try {
                Field mField = ViewPager.class.getDeclaredField("mScroller");
                mField.setAccessible(true);
                mScroller = new BannerScroller(viewPager.getContext());
                mScroller.setDuration(scrollTime);
                mField.set(viewPager, mScroller);
            } catch (Exception e) {
                Log.e(tag, e.getMessage());
            }
        }


        public MyBanner isAutoPlay(boolean isAutoPlay) {
            this.isAutoPlay = isAutoPlay;
            return this;
        }

        public MyBanner setImageLoader(ImageLoaderInterface imageLoader) {
            this.imageLoader = imageLoader;
            return this;
        }

        public MyBanner setDelayTime(int delayTime) {
            this.delayTime = delayTime;
            return this;
        }

        public MyBanner setIndicatorGravity(int type) {
            switch (type) {
                case BannerConfig.LEFT:
                    this.gravity = Gravity.LEFT | Gravity.CENTER_VERTICAL;
                    break;
                case BannerConfig.CENTER:
                    this.gravity = Gravity.CENTER;
                    break;
                case BannerConfig.RIGHT:
                    this.gravity = Gravity.RIGHT | Gravity.CENTER_VERTICAL;
                    break;
            }
            return this;
        }

        public MyBanner setBannerAnimation(Class<? extends ViewPager.PageTransformer> transformer) {
            try {
                setPageTransformer(true, transformer.newInstance());
            } catch (Exception e) {
                Log.e(tag, "Please set the PageTransformer class");
            }
            return this;
        }

        /**
         * Set the number of pages that should be retained to either side of the
         * current page in the view hierarchy in an idle state. Pages beyond this
         * limit will be recreated from the adapter when needed.
         *
         * @param limit How many pages will be kept offscreen in an idle state.
         * @return Banner
         */
        public MyBanner setOffscreenPageLimit(int limit) {
            if (viewPager != null) {
                viewPager.setOffscreenPageLimit(limit);
            }
            return this;
        }

        /**
         * Set a {@link PageTransformer} that will be called for each attached page whenever
         * the scroll position is changed. This allows the application to apply custom property
         * transformations to each page, overriding the default sliding look and feel.
         *
         * @param reverseDrawingOrder true if the supplied PageTransformer requires page views
         *                            to be drawn from last to first instead of first to last.
         * @param transformer         PageTransformer that will modify each page's animation properties
         * @return Banner
         */
        public MyBanner setPageTransformer(boolean reverseDrawingOrder, ViewPager.PageTransformer transformer) {
            viewPager.setPageTransformer(reverseDrawingOrder, transformer);
            return this;
        }

        public MyBanner setBannerTitles(List<String> titles) {
            this.titles = titles;
            return this;
        }

        public MyBanner setBannerStyle(int bannerStyle) {
            this.bannerStyle = bannerStyle;
            return this;
        }

        public MyBanner setViewPagerIsScroll(boolean isScroll) {
            this.isScroll = isScroll;
            return this;
        }

        public MyBanner setImages(List<?> imageUrls) {
            this.imageUrls = imageUrls;
            this.count = imageUrls.size();
            return this;
        }

        public void update(List<?> imageUrls, List<String> titles) {
            this.imageUrls.clear();
            this.titles.clear();
            this.imageUrls.addAll(imageUrls);
            this.titles.addAll(titles);
            this.count = this.imageUrls.size();
            start();
        }

        public void update(List<?> imageUrls) {
            this.imageUrls.clear();
            this.imageUrls.addAll(imageUrls);
            this.count = this.imageUrls.size();
            start();
        }

        public void updateBannerStyle(int bannerStyle) {
            indicator.setVisibility(GONE);
            numIndicator.setVisibility(GONE);
            numIndicatorInside.setVisibility(GONE);
            indicatorInside.setVisibility(GONE);
            bannerTitle.setVisibility(View.GONE);
            titleView.setVisibility(View.GONE);
            this.bannerStyle = bannerStyle;
            start();
        }

        public MyBanner start() {
            setBannerStyleUI();
            setImageList(imageUrls);
            setData();
            return this;
        }

        private void setTitleStyleUI() {
            if (titles.size() != imageUrls.size()) {
                throw new RuntimeException("[Banner] --> The number of titles and images is different");
            }
            if (titleBackground != -1) {
                titleView.setBackgroundColor(titleBackground);
            }
            if (titleHeight != -1) {
                titleView.setLayoutParams(new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, titleHeight));
            }
            if (titleTextColor != -1) {
                bannerTitle.setTextColor(titleTextColor);
            }
            if (titleTextSize != -1) {
                bannerTitle.setTextSize(TypedValue.COMPLEX_UNIT_PX, titleTextSize);
            }
            if (titles != null && titles.size() > 0) {
                bannerTitle.setText(titles.get(0));
                bannerTitle.setVisibility(View.VISIBLE);
                titleView.setVisibility(View.VISIBLE);
            }
        }

        private void setBannerStyleUI() {
            int visibility;
            if (count > 1) visibility = View.VISIBLE;
            else visibility = View.GONE;
            switch (bannerStyle) {
                case BannerConfig.CIRCLE_INDICATOR:
                    indicator.setVisibility(visibility);
                    break;
                case BannerConfig.NUM_INDICATOR:
                    numIndicator.setVisibility(visibility);
                    break;
                case BannerConfig.NUM_INDICATOR_TITLE:
                    numIndicatorInside.setVisibility(visibility);
                    setTitleStyleUI();
                    break;
                case BannerConfig.CIRCLE_INDICATOR_TITLE:
                    indicator.setVisibility(visibility);
                    setTitleStyleUI();
                    break;
                case BannerConfig.CIRCLE_INDICATOR_TITLE_INSIDE:
                    indicatorInside.setVisibility(visibility);
                    setTitleStyleUI();
                    break;
            }
        }

        private void initImages() {
            imageViews.clear();
            if (bannerStyle == BannerConfig.CIRCLE_INDICATOR ||
                    bannerStyle == BannerConfig.CIRCLE_INDICATOR_TITLE ||
                    bannerStyle == BannerConfig.CIRCLE_INDICATOR_TITLE_INSIDE) {
                createIndicator();
            } else if (bannerStyle == BannerConfig.NUM_INDICATOR_TITLE) {
                numIndicatorInside.setText("1/" + count);
            } else if (bannerStyle == BannerConfig.NUM_INDICATOR) {
                numIndicator.setText("1/" + count);
            }
        }

        private void setImageList(List<?> imagesUrl) {
            if (imagesUrl == null || imagesUrl.size() <= 0) {
                Log.e(tag, "Please set the images data.");
                return;
            }
            initImages();
            for (int i = 0; i < count; i++) {
                View imageView = null;
                if (imageLoader != null) {
                    imageView = imageLoader.createImageView(context);
                }
                if (imageView == null) {
                    imageView = new ImageView(context);
                }
                setScaleType(imageView);
                Object url = null;
                url = imagesUrl.get(i);
                /*if (i == 0) {
                    url = imagesUrl.get(count - 1);
                } else if (i == count + 1) {
                    url = imagesUrl.get(0);
                } else {
                    url = imagesUrl.get(i - 1);
                }*/
                imageViews.add(imageView);
                if (imageLoader != null)
                    imageLoader.displayImage(context, url, imageView);
                else
                    Log.e(tag, "Please set images loader.");
            }
        }

        private void setScaleType(View imageView) {
            if (imageView instanceof ImageView) {
                ImageView view = ((ImageView) imageView);
                switch (scaleType) {
                    case 0:
                        view.setScaleType(ScaleType.CENTER);
                        break;
                    case 1:
                        view.setScaleType(ScaleType.CENTER_CROP);
                        break;
                    case 2:
                        view.setScaleType(ScaleType.CENTER_INSIDE);
                        break;
                    case 3:
                        view.setScaleType(ScaleType.FIT_CENTER);
                        break;
                    case 4:
                        view.setScaleType(ScaleType.FIT_END);
                        break;
                    case 5:
                        view.setScaleType(ScaleType.FIT_START);
                        break;
                    case 6:
                        view.setScaleType(ScaleType.FIT_XY);
                        break;
                    case 7:
                        view.setScaleType(ScaleType.MATRIX);
                        break;
                }

            }
        }

        private void createIndicator() {
            indicatorImages.clear();
            indicator.removeAllViews();
            indicatorInside.removeAllViews();
            for (int i = 0; i < count; i++) {
                ImageView imageView = new ImageView(context);
                imageView.setScaleType(ScaleType.CENTER_CROP);
                LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(mIndicatorWidth, mIndicatorHeight);
                params.leftMargin = mIndicatorMargin;
                params.rightMargin = mIndicatorMargin;
                if (i == 0) {
                    imageView.setImageResource(mIndicatorSelectedResId);
                } else {
                    imageView.setImageResource(mIndicatorUnselectedResId);
                }
                indicatorImages.add(imageView);
                if (bannerStyle == BannerConfig.CIRCLE_INDICATOR ||
                        bannerStyle == BannerConfig.CIRCLE_INDICATOR_TITLE)
                    indicator.addView(imageView, params);
                else if (bannerStyle == BannerConfig.CIRCLE_INDICATOR_TITLE_INSIDE)
                    indicatorInside.addView(imageView, params);
            }
        }


        private void setData() {
            currentItem = 1;
            if (adapter == null) {
                adapter = new BannerPagerAdapter();
                viewPager.addOnPageChangeListener(this);
            }
            viewPager.setAdapter(adapter);
            viewPager.setFocusable(true);
            viewPager.setCurrentItem(1);
            if (gravity != -1)
                indicator.setGravity(gravity);
            if (isScroll && count > 1) {
                viewPager.setScrollable(true);
            } else {
                viewPager.setScrollable(false);
            }
            if (isAutoPlay)
                startAutoPlay();
        }

        public void setCurrentPosition(int position){
            viewPager.setCurrentItem(position);
        }


        public void startAutoPlay() {
            handler.removeCallbacks(task);
            handler.postDelayed(task, delayTime);
        }

        public void stopAutoPlay() {
            handler.removeCallbacks(task);
        }

        private final Runnable task = new Runnable() {
            @Override
            public void run() {
                if (count > 1 && isAutoPlay) {
                    currentItem = currentItem % (count + 1) + 1;
//                Log.i(tag, "curr:" + currentItem + " count:" + count);
                    if (currentItem == 1) {
                        viewPager.setCurrentItem(currentItem, false);
                        handler.post(task);
                    } else {
                        viewPager.setCurrentItem(currentItem);
                        handler.postDelayed(task, delayTime);
                    }
                }
            }
        };

        @Override
        public boolean dispatchTouchEvent(MotionEvent ev) {
//        Log.i(tag, ev.getAction() + "--" + isAutoPlay);
            if (isAutoPlay) {
                int action = ev.getAction();
                if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL
                        || action == MotionEvent.ACTION_OUTSIDE) {
                    startAutoPlay();
                } else if (action == MotionEvent.ACTION_DOWN) {
                    stopAutoPlay();
                }
            }
            return super.dispatchTouchEvent(ev);
        }

        /**
         * 返回真实的位置
         *
         * @param position
         * @return 下标从0开始
         */
        public int toRealPosition(int position) {
            int realPosition = (position - 1) % count;
            if (realPosition < 0)
                realPosition += count;
            return realPosition;
        }

        class BannerPagerAdapter extends PagerAdapter {

            @Override
            public int getCount() {
                return imageViews.size();
            }

            @Override
            public boolean isViewFromObject(View view, Object object) {
                return view == object;
            }

            @Override
            public Object instantiateItem(ViewGroup container, final int position) {
                container.addView(imageViews.get(position));
                View view = imageViews.get(position);
                if (bannerListener != null) {
                    view.setOnClickListener(new OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            Log.e(tag, "你正在使用旧版点击事件接口，下标是从1开始，" +
                                    "为了体验请更换为setOnBannerListener，下标从0开始计算");
                            bannerListener.OnBannerClick(position);
                        }
                    });
                }
                if (listener != null) {
                    view.setOnClickListener(new OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            listener.OnBannerClick(toRealPosition(position));
                        }
                    });
                }
                return view;
            }

            @Override
            public void destroyItem(ViewGroup container, int position, Object object) {
                container.removeView((View) object);
            }

        }

        @Override
        public void onPageScrollStateChanged(int state) {
            if (mOnPageChangeListener != null) {
                mOnPageChangeListener.onPageScrollStateChanged(state);
            }
            currentItem = viewPager.getCurrentItem();
            switch (state) {
                case 0://No operation
                    if (currentItem == 0) {
                        viewPager.setCurrentItem(count, false);
                    } else if (currentItem == count + 1) {
                        viewPager.setCurrentItem(1, false);
                    }
                    break;
                case 1://start Sliding
                    if (currentItem == count + 1) {
                        viewPager.setCurrentItem(1, false);
                    } else if (currentItem == 0) {
                        viewPager.setCurrentItem(count, false);
                    }
                    break;
                case 2://end Sliding
                    break;
            }
        }

        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            if (mOnPageChangeListener != null) {
                mOnPageChangeListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
            }
        }

        @Override
        public void onPageSelected(int position) {
            if (mOnPageChangeListener != null) {
                mOnPageChangeListener.onPageSelected(position);
            }
            if (bannerStyle == BannerConfig.CIRCLE_INDICATOR ||
                    bannerStyle == BannerConfig.CIRCLE_INDICATOR_TITLE ||
                    bannerStyle == BannerConfig.CIRCLE_INDICATOR_TITLE_INSIDE) {
                indicatorImages.get((lastPosition - 1 + count) % count).setImageResource(mIndicatorUnselectedResId);
                indicatorImages.get((position - 1 + count) % count).setImageResource(mIndicatorSelectedResId);
                lastPosition = position;
            }
            if (position == 0) position = count;
            if (position > count) position = 1;
            switch (bannerStyle) {
                case BannerConfig.CIRCLE_INDICATOR:
                    break;
                case BannerConfig.NUM_INDICATOR:
                    numIndicator.setText(position + "/" + count);
                    break;
                case BannerConfig.NUM_INDICATOR_TITLE:
                    numIndicatorInside.setText(position + "/" + count);
                    bannerTitle.setText(titles.get(position - 1));
                    break;
                case BannerConfig.CIRCLE_INDICATOR_TITLE:
                    bannerTitle.setText(titles.get(position - 1));
                    break;
                case BannerConfig.CIRCLE_INDICATOR_TITLE_INSIDE:
                    bannerTitle.setText(titles.get(position - 1));
                    break;
            }

        }

        @Deprecated
        public MyBanner setOnBannerClickListener(OnBannerClickListener listener) {
            this.bannerListener = listener;
            return this;
        }

        /**
         * 废弃了旧版接口，新版的接口下标是从1开始，同时解决下标越界问题
         *
         * @param listener
         * @return
         */
        public MyBanner setOnBannerListener(OnBannerListener listener) {
            this.listener = listener;
            return this;
        }

        public void setOnPageChangeListener(ViewPager.OnPageChangeListener onPageChangeListener) {
            mOnPageChangeListener = onPageChangeListener;
        }

        public void releaseBanner() {
            handler.removeCallbacksAndMessages(null);
        }
    }
